<?php
/**
 * Created by PhpStorm.
 * User: zlkmu
 * Date: 10/31/2017
 * Time: 11:19 AM
 * 用于记录某一个房间麻将过程的类
 */

class MaJongRoomRecorder{
    //用于记录玩家打牌结果的数组
    //某一次玩家打牌后的，其它玩家的可能结果组合
    //array('来自哪个玩家(from)' , '打的什么牌(pai)', 'to(打给哪个玩家)', 'peng'=>碰数组，'gang'=>杠数组, 'hu'=>胡数组)))
    public $playerDaPaiResult = array();

    //用于记录玩家摸牌结果的对象（只记录最近一次玩家摸牌的结果)
    //某一次玩家摸牌后的结果
    //array('playerID'=>, 'pai'=>, 'hu'=>true/false, 'gang'=> array('ming'=>pai/false, 'an'=>array(pai, pai)),
    // 'qiang'=>array(playerID...), 'ting'=>array(i=>array(打什么牌, array(胡的牌))))
    public $playerMoPaiResult = array();

    //用于记录整体胡的结果对象，分别为，第几局，来自哪个玩家，支付给哪个玩家，几番，胡牌还是点杠--------------------------------------------------存数据库
    //一个人toPlayer 为数字  多人为数组
    public $playerHuPaiResult = array(/*'pan'=>'', 'fromPlayer'=>'', 'toPlayer'=>'', 'fanshu'=>'', 'type'=>''*/);

    //某一次玩家打牌或摸牌后，其它玩家的选择结果，用于判断碰，杠，胡冲突的情况
    //array(type(0；摸牌，1：打牌）, playerID（等待哪个玩家决定）, pai（哪张牌）, decision:0未决定，1过，2碰，3杠，4胡)
    public $playerDecision = array();

    public $playerTuiResult = array();

    //玩家步骤记录器------------------------------------------------------------------------------------------------------------------------存数据库(一盘一盘存)
    //(盘数，'playerID'，动作（摸牌/打牌/碰牌/杠牌/胡牌/推牌), pai(哪张牌，或一个牌数组（针对推牌)), 动作后牌的结果， 动作后的结果（输赢）)
    public $playerStepRecorder = array();

    //每盘开始的时候记录的信息：包括骰子，庄，肥羊，以及其它信息-----------------------------------------------------------------------------存数据库
    public $roomRoundRecorder = array();

    //记录人和牌
    public $qiangGangRecorder=array();


    /**
     * 记录每一局的某些具体信息，如骰子，谁是庄，肥羊等
     * @param $round
     * @param $beginRoundInfo beginGame函数获取到的信息
     */
    public function recordRoundRecord($round, $beginRoundInfo){
        $this->roomRoundRecorder["round"]=$round;
        $this->roomRoundRecorder["touzi"]=$beginRoundInfo['touZi'];
        $this->roomRoundRecorder["zhuang"]=$beginRoundInfo['zhuang'];
        $this->roomRoundRecorder["feiYang"]=$beginRoundInfo['feiYang'];
    }

    /**
     * 向计步器里添加一条数据
     * @param $pan 盘数
     * @param $playerID 操作的玩家ID
     * @param $action 操作的动作（摸、打、碰、杠、胡、推）
     * @param $pai 操作的牌
     * @param $playerPai ???
     * @param $action_result  ???
     */
    public function recordPlayerStepRecord($pan, $playerID, $action, $pai, $playerPai, $action_result){
        array_push($this->playerStepRecorder, array(
            'pan'=>$pan,
            'playerID'=>$playerID,
            'action'=>$action,
            'pai'=>$pai,
            'playerPai'=>$playerPai,
            'actionResult'=>$action_result
        ));
    }

    /**
     * 获取计步器里的数组结果
     * @return array
     */
    public function getPlayerStepRecord(){
        return $this->playerStepRecorder;
    }

    /**
     * 获取推牌数组里的结果
     * @return array
     */
    public function getPlayerTuiResult(){
        return $this->playerTuiResult;
    }

    /**
     * 查询到所有没有执行操作的
     * @return array
     */
    public function getNotDecision(){
        $result=array();
        for($i=0;$i<count($this->playerDecision);$i++){
            if($this->playerDecision[$i]["decision"]==0){
                array_push($result,$this->playerDecision[$i]);
            }
        }
        return $result;
    }

    /**
     * 记录和判断玩家推牌结果
     * @param $playerID  推牌玩家ID
     * @param $tuiPai 推出来的牌数组
     * @param $huPai 推了后胡的牌数组
     * @return bool true/推成功，返回推牌所胡的牌， false/推失败，数据错误
     */
    public function recordTuiPaiResult($playerID, $tuiPai,$huPai){

        array_push($this->playerTuiResult,array("playerID"=>$playerID,"tuiPai"=>$tuiPai,"huPai"=>$huPai));
        $result=array();
        for($i=0;$i<count($this->playerDecision);$i++){
            if($this->playerDecision[$i]["decision"]==0){
                array_push($result,$this->playerDecision[$i]);
            }
        }
        return $result;
    }

    /**
     * 记录当前玩家摸牌的结果
     * @param $moPaiResult
     */
    public function recordMoPaiResult($moPaiResult){
        //每一次有人摸牌，这个结果就清空，只记录最新一次摸牌结果
        $this->playerMoPaiResult = $moPaiResult;
        //获取几个结果：如果摸牌后可以杠，摸牌后可以胡，都记录到playerDecision中，方便统一处理
        $this->playerDecision = array();

        $gangArray = $moPaiResult['gang']['an'];
        if($moPaiResult['gang']['ming'])
            array_push($gangArray, $moPaiResult['gang']['ming']);
        if(count($gangArray) != 0){
            array_push($this->playerDecision,
                array(
                    'type'=>0,
                    'playerID'=>$moPaiResult['playerID'],
                    'pai'=>$gangArray,
                    'decision'=>0));
        }
    }

    /**
     * 添加十八学士记录
     * @param $pai
     */
    public function shiBaXueShiRecord($playerID,$pai){
        array_push($this->playerDecision,
            array(
                'type'=>0,
                'playerID'=>$playerID,
                'pai'=>$pai,
                'decision'=>0));
    }

    /**
     * 记录某个玩家打牌的结果
     * @param $daPaiResult
     */
    public function recordDaPaiResult($daPaiResult){
        //每一次有人打牌，这个结果就清空，只记录最新一次打牌结果
        $this->playerDaPaiResult = $daPaiResult;
        $this->playerDecision = array();

        //记录是否需要等待玩家决定
        for($i = 0; $i < count($this->playerDaPaiResult); $i++){
            //如果打的牌其它玩家能碰，能杠，或能胡，必须等待其它玩家的反应，所以记录玩家，等待玩家响应
            if(count($this->playerDaPaiResult[$i]['hu'])!=0
                || count($this->playerDaPaiResult[$i]['peng'])!=0
                || count($this->playerDaPaiResult[$i]['gang'])!=0){
                array_push($this->playerDecision, array(
                    'type'=>1,
                    'playerID' => $this->playerDaPaiResult[$i]['to'],
                    'pai'=>$this->playerDaPaiResult[$i]['pai'],
                    'decision'=>0,
                    'peng'=>$this->playerDaPaiResult[$i]['peng'],
                    'gang'=>$this->playerDaPaiResult[$i]['gang'],
                    'hu'=>$this->playerDaPaiResult[$i]['hu']
                ));
            }
        }
    }

    /**
     * 检查是否还有可以胡牌的玩家没有做出响应
     * @param $step 玩家下一步的动作
     * @return bool true:是 false:否
     */
    public function isHuPaiPlayerUnDecision($step){
        if(!$this->playerDecision){
            return false;
        }
        if($step == 0){
            //从打牌结果里面找到可以胡牌的玩家 看它在desicion里面的决定是否为0 如果是就return true 等待
            for($i=0;$i<count($this->playerDaPaiResult);$i++){
                for($j = 0; $j < count($this->playerDecision); $j++){
                    if($this->playerDecision[$j]['playerID']==$this->playerDaPaiResult[$i]['to']
                        &&$this->playerDecision[$j]['decision']==0
                        &&count($this->playerDaPaiResult[$i]['hu'])!=0){
                        return true;
                    }
                }
            }
            return false;

        }else{
            //摸牌结果里找到抢杠胡的玩家 看它在desicion里面的决定是否为0 如果是就return true 等待
            $arr=array();
            for($i=0;$i<count($this->qiangGangRecorder);$i++){
                array_push($arr,$this->qiangGangRecorder[$i][1]);
            }
            for($j = 0; $j < count($this->playerDecision); $j++){
                if(in_array($this->playerDecision[$j]['playerID'],$arr)&&$this->playerDecision[$j]['decision']==0){
                    return true;
                }
            }
            return false;
        }

    }

    /**
     * 记录某个玩家某一次选择的结果
     * @param $playerID 玩家ID
     * @param $pai 选择的牌
     * @param $decision 选择的操作码
     * @return bool 选择结果，正确或失败
     */
    public function recordPlayerDecision($playerID, $pai, $decision){
        //如果根本没有记录数据的需求，则补充记录一下，为了统一处理
        if(count($this->playerDecision) == 0){
            array_push($this->playerDecision, array(
                'type'=>1,
                'playerID' => $playerID,
                'pai'=>$pai,
                'decision'=>$decision
            ));
            return true;
        }


        for($i = 0; $i < count($this->playerDecision); $i++){
            if($this->playerDecision[$i]['playerID'] == $playerID){

                if(is_array($this->playerDecision[$i]['pai'])){
                    if(in_array($pai, $this->playerDecision[$i]['pai'])){
                        $this->playerDecision[$i]['decision'] = $decision;
                        return true;
                    }else if(in_array($pai,$this->playerDecision[$i]['pai'][0])){
                        $this->playerDecision[$i]['decision'] = $decision;
                        return true;
                    }
                }
                else{
                    if($this->playerDecision[$i]['pai'] == $pai){
                        $this->playerDecision[$i]['decision'] = $decision;
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 判断是否所有玩家都做了决定
     * @return bool
     */
    public function isEveryOneDecisied(){
        for($i = 0; $i < count($this->playerDecision); $i++){
            if($this->playerDecision[$i]['decision'] == 0){
                return false;
            }
        }
        return true;
    }

    /**
     * 辅助函数，判断是否有玩家做出了胡牌决定
     * @return bool
     */
    private function hasPlayerHuPai(){
        for($i = 0; $i < count($this->playerDecision); $i++){
            if($this->playerDecision[$i]['decision'] == RECORDER_HUPAI){
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否为当前放炮玩家杠上炮的函数
     * 基本思路是，因为记录器在胡牌之前，如果是杠上炮，其最后三步应该为：
     * 杠牌-》摸牌-》打牌，即如果玩家满足这个过程，那就是杠上炮
     * @param $playerID
     * @return true/false
     */
    public function isGangShangPao($playerID){
        $id = count($this->playerStepRecorder)-1;

        if($id<2){
            return false;
        }

        $step1 = $this->playerStepRecorder[$id-2];
        $step2 = $this->playerStepRecorder[$id-1];
        $step3 = $this->playerStepRecorder[$id];

        if($step1['playerID'] == $playerID && $step2['playerID'] == $playerID &&
            $step3['playerID'] == $playerID && $step1['action'] == RECORDER_GANGPAI &&
            $step2['action'] == RECORDER_MOPAI && $step3['action'] == RECORDER_DAPAI){
            return true;
        }

        return false;
    }

    /**
     * 判断是否为当前玩家杠上自摸的函数
     * 基本思路是，因为记录器在胡牌之前，如果是杠上自摸，其最后2步应该为：
     * 杠牌-》摸牌，即如果玩家满足这个过程，那就是杠上自摸
     * @param $playerID
     * @return true/false
     */
    public function isGangShangHu($playerID){
        $id = count($this->playerStepRecorder)-1;
        if($id<1){
            return false;
        }
        $step1 = $this->playerStepRecorder[$id-1];
        $step2 = $this->playerStepRecorder[$id];

        if($step1['playerID'] == $playerID && $step2['playerID'] == $playerID &&
            $step1['action'] == RECORDER_GANGPAI && $step2['action'] == RECORDER_MOPAI ){
            return true;
        }
        return false;
    }

    /**
     * 判断某个玩家胡牌是否为抢杠胡的函数
     * @param $playerID 胡牌的玩家
     * @return mixed 抢的玩家的ID或false
     */
    public function isQiangGangHu($playerID,$pai){
        for($i=0;$i<count($this->qiangGangRecorder);$i++){
            if($playerID==$this->qiangGangRecorder[$i][1]&&$pai==$this->qiangGangRecorder[$i][0]){
                return true;
            }
        }
        return false;
    }

    /**
     * 判断某个玩家胡牌是否为天胡的函数
     * @param $playerID
     * @return bool
     */
    public function isTianHu($playerID){
        if(count($this->playerStepRecorder)==1
            &&$this->playerStepRecorder[0]['playerID']==$playerID
            &&$this->playerStepRecorder[0]['action'] == RECORDER_MOPAI){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 判断某个玩家胡牌是否为地胡的函数
     * @param $playerID
     * @return bool
     */
    public function isDiHu($playerID){
        if(count($this->playerStepRecorder)>1){
            $tempStep=array();
            for($i=0;$i<count($this->playerStepRecorder);$i++){
                if($this->playerStepRecorder[$i]['action']!=RECORDER_GANGPAI
                    &&$this->playerStepRecorder[$i]['action']!=RECORDER_PENGPAI
                    &&$this->playerStepRecorder[$i]['action']!=RECORDER_TUIPAI){

                    if($this->playerStepRecorder[$i]["playerID"]==$playerID){
                        array_push($tempStep,$this->playerStepRecorder[$i]);
                    }
                }else {
                    return false;
                }
            }

            //地胡当前人只有一次操作
            if(count($tempStep)==1){
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }



    /**
     * 如果所有玩家都决定了，则得到最终决定数组
     * @return mixed array=>('playerID', 'pai', 'type'，'action') => (玩家ID， 牌， 决定的类型,最终的动作) 或 PLAYER_MOPAI_REQUEST
     */
    public function getFinalDecision(){

        $result = array();
        //找到所有可能胡牌的人
        for($i = 0; $i < count($this->playerDecision); $i++){
            if($this->playerDecision[$i]['decision'] == RECORDER_HUPAI){
                array_push($result, array('playerID'=>$this->playerDecision[$i]['playerID'],
                    'pai'=>$this->playerDecision[$i]['pai'], 'type'=>RECORDER_HUPAI, 'action'=>RECORDER_HUPAI));

                array_splice($this->playerDecision,$i,1);//删除掉当前做了决定的人，以免一炮多响时出错
            }
        }

        //找到做出碰牌或者杠牌决定的人
        for($i = 0; $i < count($this->playerDecision); $i++){
            //如果玩家是碰牌或者杠牌
            $decision = $this->playerDecision[$i]['decision'];
            if($decision == RECORDER_PENGPAI || $decision == RECORDER_GANGPAI){
                //如果没有玩家胡牌, 则最终结果为碰牌或者杠牌
                if(!$this->hasPlayerHuPai()){
                    $type = $decision;
                }
                //如果有玩家胡牌，则最终结果为不能碰牌或杠牌
                else{
                    $type = PLAYER_CANNOT_DO;
                }
                array_push($result, array('playerID'=>$this->playerDecision[$i]['playerID'],
                    'pai'=>$this->playerDecision[$i]['pai'], 'type'=>$decision, 'action'=>$type));
            }
        }

        //这时候有两种情况，一种是都记录了过程，一种是都过牌了,这时候需要要求下一家摸牌
        if(count($result) == 0){
            return PLAYER_MOPAI_REQUEST;
        }
        else{
            return $result;
        }

    }


    /**
     * 记录玩家胡牌操作到playerHuPaiResult
     * @param $pan 盘数
     * @param $fromPlayer 被胡的玩家数组
     * @param $toPlayer 胡的玩家ID
     * @param $fanshu 胡的番数
     * @param $type 胡的类型（胡时为0 杠时为杠的类型1/2）
     */
    public function recordHuPai($pan, $fromPlayer, $toPlayer, $fanshu, $type){
        array_push($this->playerHuPaiResult, array('pan'=>$pan, 'fromPlayer'=>$fromPlayer, 'toPlayer'=>$toPlayer, 'fanshu'=>$fanshu, 'type'=>$type));
    }

    /**
     * 记录玩家杠牌操作到playerHuPaiResult
     * @param $pan 盘数
     * @param $fromPlayer 被杠的玩家数组
     * @param $toPlayer 杠的玩家ID
     * @param $fanshu 杠的番数
     * @param $type 胡的类型（胡时为0 杠时为杠的类型1/2）
     */
    public function recordGangPai($pan, $fromPlayer, $toPlayer, $fanshu, $type){
        array_push($this->playerHuPaiResult, array('pan'=>$pan, 'fromPlayer'=>$fromPlayer, 'toPlayer'=>$toPlayer, 'fanshu'=>$fanshu, 'type'=>$type));
    }

    /**
     * 检查某个玩家能否碰牌
     * @return PLAYER_WAIT, PLAYER_CANNOT_DO, true
     */
    function canPlayerPeng(){
        //如果还有玩家没做决定
        if(!$this->isEveryOneDecisied()){
            return PLAYER_WAIT;
        }
        //如果都做了决定，查看结果数组，返回ROOM做相关工作
        //返回数据为：array('PlayerID', 'pai', 'decision');
        else{
            return $this->getFinalDecision();
        }
    }

    /**
     * 检查某个玩家能否杠牌
     * @return PLAYER_WAIT, array()
     */
    function canPlayerGang(){

        //如果还有玩家没做决定
        if(!$this->isEveryOneDecisied()){
            return PLAYER_WAIT;
        }
        else{
            return $this->getFinalDecision();
        }
    }

    /**
     * 分发检查碰、杠、胡是否合法的函数
     * @param $playerID 做出动作的玩家ID
     * @param $pai 对应的牌
     * @param $action 做出的动作
     * @param $step 是摸牌还是打牌
     * @return bool true/false
     */
    function checkActionLegel($playerID, $pai, $action, $step){
        if($step == 0){
            return $this->doCheckDaPaiActionLegel($playerID, $pai, $action);
        }
        else{
            return $this->doCheckMoPaiActionLegel($playerID, $pai, $action);
        }
    }

    /**
     * 检查摸牌后结果是否合法的函数，摸牌后可能的动作只有3个：胡牌，杠牌，被抢杠
     * @param $playerID  目前做出动作的玩家（有可能是摸牌玩家自己，也有可能是抢杠玩家）
     * @param $pai 对应的牌
     * @param $action  对应的动作
     * @return bool true/false
     */
    private function doCheckMoPaiActionLegel($playerID, $pai, $action){
        //array('playerID'=>, 'pai'=>, 'hu'=>true/false, 'gang'=> array('ming'=>pai/false, 'an'=>array(pai, pai)),
        // 'qiang'=>array(playerID...), 'ting'=>array(i=>array(打什么牌, array(胡的牌))))
        switch($action){
            case RECORDER_GANGPAI:
                //print_r($this->playerMoPaiResult);
                if($this->playerMoPaiResult['playerID'] == $playerID){
                    $gang = $this->playerMoPaiResult['gang'];
                    if(in_array($pai,$gang['ming']) || in_array($pai,$gang['an'])){
                        return true;
                    }
                    else{
                        return false;
                    }
                }
                else{
                    return false;
                }
            case RECORDER_HUPAI:
                if($this->playerMoPaiResult['playerID'] == $playerID && $this->playerMoPaiResult['pai'] == $pai){
                    return true;
                }
                $gang = $this->playerMoPaiResult['gang'];
                if(in_array($pai,$gang['ming'])){
                    return true;
                }
                return false;
        }
    }

    /**
     * 检查打牌后结果是否合法的函数，打牌后可能的动作只有3个：胡牌，杠牌，碰牌
     * @param $playerID  目前做出动作的玩家（有可能是摸牌玩家自己，也有可能是抢杠玩家）
     * @param $pai 对应的牌
     * @param $action  对应的动作
     * @return bool  true/false
     */
    private function doCheckDaPaiActionLegel($playerID, $pai, $action){
        for($i = 0; $i < count($this->playerDaPaiResult); $i++){
            switch($action){
                case RECORDER_HUPAI:
                    if(count($this->playerDaPaiResult[$i]['hu'])!=0 &&
                        $this->playerDaPaiResult[$i]['to'] == $playerID &&
                        $this->playerDaPaiResult[$i]['pai'] == $pai){
                        return true;
                    }

                case RECORDER_PENGPAI:
                    if($this->playerDaPaiResult[$i]['peng'] &&
                        $this->playerDaPaiResult[$i]['to'] == $playerID &&
                        $this->playerDaPaiResult[$i]['pai'] == $pai){
                        return true;
                    }

                case RECORDER_GANGPAI:
                    if($this->playerDaPaiResult[$i]['gang'] &&
                        $this->playerDaPaiResult[$i]['to'] == $playerID &&
                        $this->playerDaPaiResult[$i]['pai'] == $pai){
                        return true;
                    }
            }
        }
        return false;
    }


    /**
     * 检查用户是否是过手杠情况
     * @param $playerID
     * @param $pai
     * @return bool true/false
     */
    function isGuoShouGang($playerID,$pai){
        $tempArray=array();
        //先找出所有此人此盘[不为过]的操作
        for($i=0;$i<count($this->playerStepRecorder);$i++){
            if($this->playerStepRecorder[$i]["playerID"]==$playerID&&$this->playerStepRecorder[$i]["action"]!=RECORDER_GUOPAI){
                array_push($tempArray,$this->playerStepRecorder[$i]);
            }
        }

        //从后向前检测此用户的操作是否是摸->打->碰 且此次需要杠的牌是碰的牌
        $temp1=end($tempArray);//摸操作
        $temp2=prev($tempArray);//打操作
        $temp3=prev($tempArray);//碰操作

        //看顺序是否满足且碰牌是当前牌
        if($temp1["action"]==RECORDER_MOPAI&&$temp2["action"]==RECORDER_DAPAI&&$temp3["action"]==RECORDER_PENGPAI&&$temp3["pai"]==$pai){
            return true;
        }else{
            return false;
        }
    }

    public function recordMoPaiMingGangResult($qiangGang)
    {
        //如果附带了抢杠结果，则玩家是明杠，有人可以胡
        for ($i = 0; $i < count($qiangGang); $i++) {
            array_push($this->playerDecision,
                array(
                    'type' => 0,
                    'playerID' => $qiangGang[$i][1],
                    'pai' => $qiangGang[$i][0],
                    'decision' => 0
                ));
        }

        $this->qiangGangRecorder=$qiangGang;
    }



    private function hasPlayerNeedPengGangHu(){
        for($i = 0; $i < count($this->playerDecision); $i++){
            if($this->playerDecision[$i]['decision'] == PLAYER_PENGPAI ||
                $this->playerDecision[$i]['decision'] == PLAYER_GANGPAI ||
                $this->playerDecision[$i]['decision'] == PLAYER_HUPAI){
                return true;
            }
        }
        return false;
    }


}



?>